<?php

class Controller_Admin_Crud extends Controller_Admin 
{
	/**
	 * Paginator itemCountPerPage property.
	 * 
	 * @var integer
	 */
	protected $_itemCountPerPage = 25;
	
	/**
	 * Specified table instance
	 * @var Crud_Db_Table_Abstract
	 */
	protected $_table;
	
	/**
	 * Specified row in table.
	 * @var Db_Row
	 */
	protected $_row;
	
	public function preDispatch()
	{
		parent::preDispatch();
		$navigation = new Crud_Navigation();
		$this->view->navigation($navigation);
		
		$crumbs = $this->view->navigation()->breadcrumbs(); 
		$crumbs->setRenderInvisible(true);
		$this->view->title = strip_tags($crumbs);
	}

	public function indexAction() {}

	public function listAction()
	{
		$table = $this->_getTable();
		
		$columns = $table->getColumns();
		foreach ($columns  as $key => $column) {
			if (!$column->showInList()) {
				unset($columns[$key]);
			}
		}
		
		$this->view->columns = $columns;
		
		$select = $this->_getListSelect();
		$paginator = $this->_getPaginator($select);
		
		// Change values with Foreign key values
		$rowset = array();
		foreach ($paginator as $row) {
			$row = $row->toArray();
			foreach ($row as $column => &$value) {
				$column = $table->getColumn($column);
				if ($column->isFK()) {
					$value = $column->getFKValue($value);
				}
			}
			
			$rowset[] = $row;
		}
		
		$this->view->rowset = $rowset;
	}
	
	/**
	 * Create select query for list action by request object.
	 * 
	 * @return Zend_Db_Select
	 */
	protected function _getListSelect()
	{
		$table = $this->_getTable();
		$select = $table->select();
		// Order condition
		$orderBy = $this->_getParam('orderBy');
		if ($orderBy) {
			$ascOrDesc = ($this->_getParam('orderDesc') == 1) ? 'desc' : 'asc';
			$select->order("$orderBy $ascOrDesc");
		}
		
		// Where conditions
		$search = $this->_getParam('search', array());
		foreach ($search as $column => $value) {
			if ($value === '' || $value === null) continue;
			
			$column = new Crud_Db_Table_Column($table, $column);
			if ($column->isFK()) {
				$select->where("`{$column->getName()}` = ?", $value);
			} else {
				$value = addslashes($value);
				$value = str_replace('%', '\%', $value);
				$select->where("`{$column->getName()}` like '%$value%'");
			}
		}
		
		$search = $this->_getParam('m2msearch', array());
		foreach ($search as $m2m => $value) {
			if (!$value) continue;
			preg_match('/^(.+?)__(.+)$/', $m2m, $result);
			$m2mTable = new Crud_Db_Table($result[1]);
			$m2mColumn = $result[2];
			
			$column = $m2mTable->getFKColumnFor($table);
			
			$select->join(
				$m2mTable->getTableName(), 
				"`{$m2mTable->getTableName()}`.`{$column->getName()}` = `{$table->getTableName()}`.`id`",
				array()
			);
			$select->where("`{$m2mTable->getTableName()}`.$m2mColumn = ?", $value);
		}
		
		return $select;
	}
	
	/**
	 * Return paginator by Zend_Db_Table_Select object.
	 * 
	 * @param $select Zend_Db_Table_Select
	 * @return Zend_Paginator
	 */
	protected function _getPaginator($select)
	{
		Zend_View_Helper_PaginationControl::setDefaultViewPartial('paginator.phtml');
		
		$adapter = new Zend_Paginator_Adapter_DbTableSelect($select);
		$paginator = new Zend_Paginator($adapter);
		$paginator->setItemCountPerPage($this->_itemCountPerPage);
		$paginator->setCurrentPageNumber($this->_getParam('page'));

		$this->view->paginator = $paginator;
		return $paginator;
	}
	
	public function ajaxListAction()
	{
		$this->_ajaxOnly();
		$this->listAction();
	}
	
	public function ajaxPaginatorAction()
	{
		$this->_ajaxOnly();
		$this->listAction();
	}
	
	public function addAction()
	{
		$this->_item();
	}
	
	public function editAction()
	{
		$this->_item();
	}
	
	public function _item()
	{
		$table = $this->_getTable();
		$row = $this->_getRow();
		
		$form = new Crud_Form($table);
		$form->setCrudConfig($table->getConfig());
		$form->setDefaultsByRow($row);
		$this->view->form = $form;
		
		$params = $this->_getAllParams();
		if ($this->getRequest()->isPost() && $form->isValid($params)) {
			// Strart transaction and save/update row.
			$connection = Db::getConnection();
			$connection->beginTransaction();
			try {
				$row->setForm($form);
				$connection->commit();
			} catch (Zend_Db_Exception $e) {
				$message = $e->getMessage();
				if (stripos($message, 'Duplicate entry') !== false) {
					$message = 'Запись с такими параметрами уже существует';
				}
				
				$form->addError($message);
				$connection->rollBack();
				return;
			}
			
			// Then redirect to list.
			$this->_goto(array(
				'action' => 'list', 
				'table' => $this->_getParam('table'), 
				'id' => null
			));
		}
	}
	
	public function deleteAction()
	{
		$this->_disableView();
		$this->_ajaxOnly();
		
		$row = $this->_getRow();
		
		// Start transaction for we can restore all selected row when we have error
		$connection = Db::getConnection();
		$connection->beginTransaction();
		try {
			$row->delete();
			$connection->commit();
			$result = 'success';
		} catch (Exception $e) {
			$connection->rollBack();
			$result = $e->getMessage();
		}
		
		$this->_setJson(array('result' => $result));
	}
	
	/**
	 * Get Table object by table name in request.
	 *
	 * @return Crud_Db_Table
	 */
	protected function _getTable()
	{
		if ($this->_table instanceof Crud_Db_Table_Abstract) {
			return $this->_table;
		}

		$table = $this->_getParam('table');
		if (!Crud_Config::getInstance()->$table) {
			throw new Exception("Table `$table` not exists in Config");
		}
		
		$table = new Crud_Db_Table($table);
		return $table;
	}
	
	/**
	 * Getting row object by id in Request.
	 *
	 * @return Crud_Db_Table_Row
	 */
	protected function _getRow()
	{
		if ($this->_row instanceof Crud_Db_Table_Row) {
			return $this->_row;
		}
		
		$table = $this->_getTable();
		$id = $this->_getParam('id');
		if (!$id) {
			return $table->createRow();
		}

		$row = $table->find($id)->current();
		if (!$row) {
			throw new Exception('Row is not exists');
		}
		
		$row = new Crud_Db_Table_Row($table, $row);
		return $row;
	}
}